package com.meizu.utils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/* BaseServlet的编写目的：
    1、完成部分请求前置操作（如设置编码，生成常用操作对象session等）
    2、让一个Servlet可以处理多个请求
    3、简化重定向、转发等操作
    4、统一的错误处理
 * @author SMILE.Huang
 * @date 2022-05-31 15:15
 */
public abstract class BaseServlet extends HttpServlet {
	//全局的session对象，子类可以继承并获得
	public HttpSession session;

	/**抽象方法，
	 * 要求子类必须重写该方法。
	 * 没有参数时，默认的处理方法。一般是Servlet第一次请求的处理方法（类似于原来的doGet）
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public abstract String excute(HttpServletRequest request,
								  HttpServletResponse response) throws Exception;

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//1、设置字符集编码格式
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		session = request.getSession();
		PrintWriter out =null;
		try{
			//封装转发和重定向
			//从请求参数中获取v（请求的方法）
			String v = request.getParameter("v");
			//配置默认方法
			String method = "excute";
			if(v!=null && !"".equals(v)) {
				method=v;
			}
			// 从当前Class对象中，获取对应的方法对象
			Method m = this.getClass().getDeclaredMethod(method, HttpServletRequest.class,HttpServletResponse.class);
			//invoke执行对应的方法
			Object result = m.invoke(this, request,response);
			//判断方法是否有返回类型
			if(result!=null) {
				if(result.toString().startsWith("f:")) {
					//转发
					forward(request,response,result.toString().substring(2));
				}else if(result.toString().startsWith("r:")) {
					//重定向
					redirect(response,result.toString().substring(2));
				}else {
					//定义响应对象的内容类型，固定返回json对象
					//response.setContentType("application/json;charset=utf-8");
					//这是ajax的请求
					out = response.getWriter();
					//直接输出结果
					out.print(result.toString());
					out.flush();
					out.close();
				}
			}
		}catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
			System.err.println("服务器参数错误。。。。");
			//在控制台输出错误信息
			e.printStackTrace();
			//将错误存储到session中
			session.setAttribute("_err", "服务器发生错误-"+e.getMessage());
			try {
				//转发到/WEB-INF/views/error.jsp页面
				forward(request, response,"error");
			} catch (ServletException | IOException e1) {
				e1.printStackTrace();
			}
		}catch (Exception ex){
			System.err.println("服务器报错了，请看下面的错误信息");
			//在控制台输出错误信息
			ex.printStackTrace();
			//将错误存储到session中
			session.setAttribute("_err", "服务器发生错误-"+ex.getMessage());
			try {
				//转发到/WEB-INF/views/error.jsp页面
				forward(request, response,"error");
			} catch (ServletException | IOException e1) {
				e1.printStackTrace();
			}
		}
		finally {
			if(out!=null)
				out.close();
		}
	}

	/**
	 * 转发的封装方法
	 * @param req
	 * @param resp
	 * @param pageName	要跳转的JSP的页面名字
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void forward(HttpServletRequest req,
						   HttpServletResponse resp,
						   String pageName) throws ServletException, IOException {
		String prefix = "/WEB-INF/jsp/";/*根据自己的实际存储页面前缀来调整*/
		String suffix = ".jsp";
		req.getRequestDispatcher(prefix+pageName+suffix).forward(req,resp);
	}

	/**
	 * 重定向的封装方法
	 * @param resp
	 * @param servletName		要跳转的Servlet的名字
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void redirect(HttpServletResponse resp,
							String servletName) throws ServletException, IOException {
		resp.sendRedirect(servletName);
	}
}
